package main

import (
	"fmt"
	"log"
	"os"
	"reflect"
	"strings"

	"game-simple/internal/framework/auth/models"
	"game-simple/internal/infrastructure/config"
	"game-simple/internal/infrastructure/core"
	"game-simple/internal/infrastructure/database"

	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

// 模型注册表
var modelRegistry = map[string]interface{}{
	// 预注册已知模型（作为默认值）
	"UserModel":      &models.UserModel{},
	"auth.UserModel": &models.UserModel{},
	// 更多模型将在扫描时自动注册
}

var modelsScanned = false

// initModels 初始化模型注册表（延迟执行）
func initModels() {
	if modelsScanned {
		return
	}
	modelsScanned = true

	// 自动扫描并注册所有模型
	if err := scanModulesForModels(); err != nil {
		// 扫描失败不影响使用，使用预注册的模型
		fmt.Printf("⚠️  自动扫描模型失败，使用预注册模型: %v\n", err)
	}
}

// generateSQLFromModel 从 GORM 模型生成 SQL
func generateSQLFromModel(modelName string, migrationName string) {
	// 确保模型已扫描
	initModels()

	// 检查模型是否存在
	model, ok := modelRegistry[modelName]
	if !ok {
		log.Fatalf("模型 '%s' 未找到\n可用模型: %s", modelName, getAvailableModels())
	}

	// 尝试加载配置和初始化数据库（用于解析 GORM schema）
	// 如果失败，尝试创建临时数据库连接用于解析模型
	var db *gorm.DB
	configPath := "cmd/web/config.yaml"

	if err := config.LoadConfig(configPath); err != nil {
		// 如果配置文件不存在，尝试使用默认路径
		configPath = "cmd/h5/config.yaml"
		if err := config.LoadConfig(configPath); err != nil {
			// 配置加载失败，使用临时数据库连接
			fmt.Printf("⚠️  无法加载配置，尝试创建临时数据库连接解析模型结构\n")
			db = createMemoryDB()
		} else {
			// 配置加载成功，尝试初始化数据库
			if err := core.Init(); err != nil {
				fmt.Printf("⚠️  无法连接数据库，尝试创建临时数据库连接解析模型结构\n")
				db = createMemoryDB()
			} else {
				defer core.Close()
				db = database.GetDB()
				if db == nil {
					db = createMemoryDB()
				}
			}
		}
	} else {
		// 配置加载成功，尝试初始化数据库
		if err := core.Init(); err != nil {
			fmt.Printf("⚠️  无法连接数据库，尝试创建临时数据库连接解析模型结构\n")
			db = createMemoryDB()
		} else {
			defer core.Close()
			db = database.GetDB()
			if db == nil {
				db = createMemoryDB()
			}
		}
	}

	// 生成 CREATE TABLE SQL
	// 如果 db 为 nil，GenerateCreateTableSQL 会失败，但我们仍然尝试
	var createSQL string
	var err error
	if db != nil {
		createSQL, err = database.GenerateCreateTableSQL(db, model)
	} else {
		err = fmt.Errorf("无法创建数据库连接用于解析模型")
	}

	if err != nil {
		// 如果数据库连接失败，使用反射方式直接解析模型
		fmt.Printf("⚠️  数据库连接失败，使用反射方式解析模型结构\n")
		createSQL = generateSQLFromSchema(model)
		if createSQL == "" {
			log.Fatalf("生成 CREATE TABLE SQL 失败: %v\n提示: 请确保数据库可以连接，或者先创建空白迁移文件再手动编写 SQL", err)
		}
	}

	// 美化 SQL（添加适当的缩进）
	createSQL = formatSQL(createSQL)

	// 生成 DROP TABLE SQL
	var dropSQL string
	if db != nil {
		dropSQL, err = database.GenerateDropTableSQL(db, model)
		if err != nil {
			log.Fatalf("生成 DROP TABLE SQL 失败: %v", err)
		}
	} else {
		// 如果无法解析，至少生成一个基本的 DROP TABLE
		// 尝试从模型获取表名
		if tn, ok := model.(interface{ TableName() string }); ok {
			dropSQL = fmt.Sprintf("DROP TABLE IF EXISTS `%s`;", tn.TableName())
		} else {
			// 从模型类型名推断
			modelType := reflect.TypeOf(model)
			if modelType.Kind() == reflect.Ptr {
				modelType = modelType.Elem()
			}
			tableName := strings.ToLower(modelType.Name()) + "s"
			dropSQL = fmt.Sprintf("DROP TABLE IF EXISTS `%s`;", tableName)
		}
	}

	// 如果没有指定迁移名称，从模型名生成
	if migrationName == "" {
		migrationName = generateMigrationName(modelName)
	}

	// 创建迁移文件
	migrationsDir := "internal/infrastructure/database/migrations"
	version := getNextVersion(migrationsDir)
	filename := fmt.Sprintf("%s/%s_%s.sql", migrationsDir, version, migrationName)

	// 构建迁移文件内容
	content := fmt.Sprintf(`-- UP
-- 自动生成自模型: %s
%s

-- DOWN
%s
`, modelName, createSQL, dropSQL)

	if err := os.WriteFile(filename, []byte(content), 0644); err != nil {
		log.Fatalf("创建迁移文件失败: %v", err)
	}

	fmt.Printf("✅ 成功生成迁移文件: %s\n", filename)
	fmt.Printf("📝 模型: %s\n", modelName)
	fmt.Printf("📄 迁移名称: %s\n", migrationName)
}

// generateMigrationName 从模型名生成迁移名称
func generateMigrationName(modelName string) string {
	// 移除 Model 后缀
	name := strings.TrimSuffix(modelName, "Model")
	// 转换为 snake_case 并添加 create_ 前缀
	name = toSnakeCase(name)
	return fmt.Sprintf("create_%s_table", strings.ToLower(name))
}

// toSnakeCase 转换为 snake_case
func toSnakeCase(s string) string {
	var result strings.Builder
	for i, r := range s {
		if i > 0 && r >= 'A' && r <= 'Z' {
			result.WriteByte('_')
		}
		result.WriteRune(r)
	}
	return strings.ToLower(result.String())
}

// getAvailableModels 获取可用模型列表
func getAvailableModels() string {
	initModels()

	models := make([]string, 0, len(modelRegistry))
	seen := make(map[string]bool)

	// 优先显示完整名称（module.Model）
	for name := range modelRegistry {
		if strings.Contains(name, ".") {
			models = append(models, name)
			seen[name] = true
		}
	}

	// 添加未显示的短名称
	for name := range modelRegistry {
		if !strings.Contains(name, ".") && !seen[name] {
			models = append(models, name)
		}
	}

	return strings.Join(models, ", ")
}

// listAllModels 列出所有可用模型
func listAllModels() {
	initModels()

	fmt.Println("\n📋 可用的模型列表:")
	fmt.Println("=" + strings.Repeat("=", 50))

	// 按模块分组显示
	moduleMap := make(map[string][]string)
	var shortNames []string

	for name := range modelRegistry {
		if strings.Contains(name, ".") {
			parts := strings.Split(name, ".")
			moduleName := parts[0]
			modelName := parts[1]
			moduleMap[moduleName] = append(moduleMap[moduleName], modelName)
		} else {
			shortNames = append(shortNames, name)
		}
	}

	// 显示按模块分组的模型
	for moduleName, modelNames := range moduleMap {
		fmt.Printf("\n📦 模块: %s\n", moduleName)
		for _, modelName := range modelNames {
			fmt.Printf("   - %s (或使用: %s.%s)\n", modelName, moduleName, modelName)
		}
	}

	// 显示短名称（如果存在）
	if len(shortNames) > 0 {
		fmt.Printf("\n📝 短名称:\n")
		for _, name := range shortNames {
			fmt.Printf("   - %s\n", name)
		}
	}

	fmt.Println("\n" + strings.Repeat("=", 51))
}

// createMemoryDB 创建一个用于解析模型的临时 GORM 实例
// 即使无法连接数据库，也能解析模型结构
func createMemoryDB() *gorm.DB {
	// 使用 schema 包直接解析模型（不需要数据库连接）
	// 但由于 GenerateCreateTableSQL 需要 *gorm.DB，我们创建一个内存数据库连接
	// 使用 MySQL 驱动，即使连接失败，GORM 也会创建一个实例（虽然无法执行查询）
	// 实际上，我们可以直接使用 schema 包来解析，但为了兼容现有代码，先尝试连接
	dsn := "root:password@tcp(127.0.0.1:1)/temp?charset=utf8mb4&parseTime=True&loc=Local"
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		// 连接失败，但 GORM 可能仍然创建了实例
		// 如果 err != nil，通常意味着 Open 失败，返回的 db 可能为 nil
		// 但我们仍然尝试使用它，因为 Parse 可能不需要真实连接
		if db == nil {
			// 如果完全失败，尝试使用 schema 包直接解析（但这需要修改 GenerateCreateTableSQL）
			// 为了简化，我们返回一个标记值
			return nil
		}
	}
	return db
}

// generateSQLFromSchema 使用 schema 包直接解析模型（不需要数据库连接）
func generateSQLFromSchema(model interface{}) string {
	// 使用 schema 包解析模型
	// 这是一个简化的实现，主要处理基本字段类型
	modelType := reflect.TypeOf(model)
	if modelType.Kind() == reflect.Ptr {
		modelType = modelType.Elem()
	}

	// 获取表名
	tableName := ""
	if tn, ok := model.(interface{ TableName() string }); ok {
		tableName = tn.TableName()
	} else {
		tableName = strings.ToLower(modelType.Name()) + "s"
	}

	var sb strings.Builder
	sb.WriteString(fmt.Sprintf("CREATE TABLE IF NOT EXISTS `%s` (\n", tableName))

	// 遍历字段
	fieldCount := 0
	for i := 0; i < modelType.NumField(); i++ {
		field := modelType.Field(i)
		if !field.IsExported() {
			continue
		}

		fieldName := getDBFieldName(field)
		if fieldName == "" {
			continue
		}

		if fieldCount > 0 {
			sb.WriteString(",\n")
		}

		fieldSQL := generateFieldSQLFromReflect(field)
		if fieldSQL != "" {
			sb.WriteString("    " + fieldSQL)
			fieldCount++
		}
	}

	sb.WriteString("\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;")
	return sb.String()
}

// getDBFieldName 从结构体字段获取数据库字段名
func getDBFieldName(field reflect.StructField) string {
	gormTag := field.Tag.Get("gorm")
	if gormTag != "" {
		// 解析 column:xxx
		parts := strings.Split(gormTag, ";")
		for _, part := range parts {
			if strings.HasPrefix(part, "column:") {
				return strings.TrimPrefix(part, "column:")
			}
		}
	}
	// 转换为 snake_case
	return toSnakeCase(field.Name)
}

// generateFieldSQLFromReflect 从反射字段生成字段 SQL
func generateFieldSQLFromReflect(field reflect.StructField) string {
	fieldName := getDBFieldName(field)
	if fieldName == "" {
		return ""
	}

	var parts []string
	parts = append(parts, fmt.Sprintf("`%s`", fieldName))

	// 获取类型
	gormTag := field.Tag.Get("gorm")
	dataType := getMySQLTypeFromReflect(field.Type)

	// 检查 gorm tag 中的 type
	if strings.Contains(gormTag, "type:") {
		tagParts := strings.Split(gormTag, ";")
		for _, part := range tagParts {
			if strings.HasPrefix(part, "type:") {
				dataType = strings.TrimPrefix(part, "type:")
				break
			}
		}
	}

	parts = append(parts, dataType)

	// 主键
	if strings.Contains(gormTag, "primarykey") || strings.Contains(gormTag, "primaryKey") {
		if strings.Contains(strings.ToLower(dataType), "int") {
			parts = append(parts, "AUTO_INCREMENT")
		}
		parts = append(parts, "PRIMARY KEY")
	}

	// NOT NULL (检查字段类型是否为指针，指针通常可为 NULL)
	isPointer := field.Type.Kind() == reflect.Ptr
	if strings.Contains(gormTag, "not null") {
		parts = append(parts, "NOT NULL")
	} else if !isPointer && !strings.Contains(strings.ToLower(dataType), "timestamp") {
		// 非指针类型通常为 NOT NULL（除非是 timestamp）
		// 但 time.Time 可以为 NULL（取决于 gorm tag）
		if strings.Contains(dataType, "TIMESTAMP") && !strings.Contains(gormTag, "not null") {
			// TIMESTAMP 可能为 NULL
			parts = append(parts, "NULL")
		} else if !strings.Contains(dataType, "TIMESTAMP") {
			parts = append(parts, "NOT NULL")
		}
	}

	// DEFAULT
	if strings.Contains(gormTag, "default:") {
		tagParts := strings.Split(gormTag, ";")
		for _, part := range tagParts {
			if strings.HasPrefix(part, "default:") {
				defaultValue := strings.TrimPrefix(part, "default:")
				parts = append(parts, fmt.Sprintf("DEFAULT %s", defaultValue))
				break
			}
		}
	}

	return strings.Join(parts, " ")
}

// getMySQLTypeFromReflect 从反射类型获取 MySQL 类型
func getMySQLTypeFromReflect(typ reflect.Type) string {
	// 处理指针类型
	if typ.Kind() == reflect.Ptr {
		return getMySQLTypeFromReflect(typ.Elem())
	}

	switch typ.Kind() {
	case reflect.Bool:
		return "TINYINT(1)"
	case reflect.Int, reflect.Int8:
		return "TINYINT"
	case reflect.Int16:
		return "SMALLINT"
	case reflect.Int32:
		return "INT"
	case reflect.Int64:
		return "BIGINT"
	case reflect.Uint8:
		return "TINYINT UNSIGNED"
	case reflect.Uint16:
		return "SMALLINT UNSIGNED"
	case reflect.Uint32:
		return "INT UNSIGNED"
	case reflect.Uint64:
		return "BIGINT UNSIGNED"
	case reflect.Uint:
		// uint 在 64 位系统上通常是 BIGINT UNSIGNED
		return "BIGINT UNSIGNED"
	case reflect.Float32:
		return "FLOAT"
	case reflect.Float64:
		return "DOUBLE"
	case reflect.String:
		return "VARCHAR(255)"
	case reflect.Struct:
		// 检查是否是 time.Time
		if typ.PkgPath() == "time" && typ.Name() == "Time" {
			return "TIMESTAMP"
		}
		// 检查是否是 gorm.DeletedAt
		if strings.Contains(typ.String(), "gorm.DeletedAt") {
			return "TIMESTAMP NULL"
		}
		return "TEXT"
	case reflect.Slice, reflect.Array:
		return "BLOB"
	default:
		return "VARCHAR(255)"
	}
}

// formatSQL 格式化 SQL，添加适当的缩进
func formatSQL(sql string) string {
	// 简单的格式化：确保字段之间有适当的换行
	// 可以根据需要改进
	return sql
}

// registerModel 注册模型（供外部扩展使用）
func registerModel(name string, model interface{}) {
	// 验证模型类型
	modelType := reflect.TypeOf(model)
	if modelType.Kind() != reflect.Ptr {
		log.Fatalf("模型 '%s' 必须是指针类型", name)
	}
	if modelType.Elem().Kind() != reflect.Struct {
		log.Fatalf("模型 '%s' 必须是指向结构体的指针", name)
	}

	modelRegistry[name] = model
}
